<template>
  <view>
    <slot />
  </view>
</template>

<script setup lang="ts">
import { reactive, watch, provide } from 'vue'

type Rule =
  | { required: true; message: string; validator?: undefined; regex?: undefined }
  | { regex: RegExp; message: string; required?: undefined; validator?: undefined }
  | { validator: (val: any, rule?: any) => boolean | string | Promise<boolean | string>; message?: string; required?: undefined; regex?: undefined; [k: string]: any }

interface Props {
  modelValue: Record<string, any>
  rules?: Record<string, Array<
    | { required: boolean; message: string }
    | { regex: RegExp; message: string }
    | { validator: (val: any, rule?: any) => boolean | string | Promise<boolean | string>; message?: string; [k: string]: any }
  >>
}

const props = defineProps<Props>()

const errors = reactive<Record<string, string>>({})

function setError(prop: string, msg: string) {
  if (msg) errors[prop] = msg
  else delete errors[prop]
}

function getRules(prop: string): Rule[] {
  return props.rules?.[prop] || []
}

async function validateField(prop: string): Promise<{ valid: boolean; message: string }> {
  const value = props.modelValue?.[prop]
  const rules = getRules(prop)
  for (const r of rules) {
    if ('required' in r && !!(r as any).required) {
      const ok = !(value === undefined || value === null || String(value).trim() === '')
      if (!ok) {
        setError(prop, r.message)
        return { valid: false, message: r.message }
      }
    }
    if ('regex' in r && r.regex) {
      const ok = r.regex.test(String(value ?? ''))
      if (!ok) {
        setError(prop, r.message)
        return { valid: false, message: r.message }
      }
    }
    if ('validator' in r && typeof r.validator === 'function') {
      const res = await Promise.resolve(r.validator(value, r))
      const ok = res === true || res === '' || res === undefined
      if (!ok) {
        const msg = typeof res === 'string' && res ? res : r.message || '校验失败'
        setError(prop, msg)
        return { valid: false, message: msg }
      }
    }
  }
  setError(prop, '')
  return { valid: true, message: '' }
}

async function validate(): Promise<{ valid: boolean; errors: Record<string, string> }> {
  const allProps = Object.keys(props.rules || {})
  let valid = true
  for (const p of allProps) {
    const res = await validateField(p)
    if (!res.valid) valid = false
  }
  return { valid, errors: { ...errors } }
}

function reset() {
  Object.keys(errors).forEach(k => delete errors[k])
}

function getError(prop: string) {
  return errors[prop] || ''
}

provide('simpleFormCtx', {
  errors,
  getError,
  validateField,
  setError
})

defineExpose({ validate, validateField, reset, errors })

watch(
  () => props.modelValue,
  () => {
    // 当模型变化时不自动清空错误，交由显式校验
  },
  { deep: true }
)
</script>

<style scoped>
</style>

